/**
 * @file      log4x-c.h
 * @copyright Copyright (c) 2019, ZCW Co., Ltd. All Rights Reserved.
 * @brief     log module such as log4j in Java
 * @author    caiwang213@qq.com
 * @date      2019-01-10 09:48:16
 *
 * @note
 *  log4x-c.h C functions defines
 */
#ifndef __LOG4X_C_H__
#define __LOG4X_C_H__

#ifndef LOG4X_MACRO
#define LOG4X_MACRO

#define LOG_FORMAT(key, level, func, file, line, sync, logformat, ...) \
do { \
    log4x_push(key, level, func, file, line, sync, logformat, ##__VA_ARGS__); \
}while(0)

#define LOG_LEVEL(key, level) \
do \
{ \
    log4x_setlevel(key, level); \
} while (0)

#define LOG_RELEASE_LEVEL(key, level) \
do \
{ \
    if (!log4x_isff(key)) \
    { \
        LOG_LEVEL(key, level); \
    } \
} while (0)

#ifdef _DEBUG
/* setlevel > fromfile for debug version */
#define LOG4X_DEBUG_LEVEL(key, level) LOG_LEVEL(key, level)
#else
/* fromfile > setlevel for release version*/
#define LOG4X_DEBUG_LEVEL(key, level) LOG_RELEASE_LEVEL(key, level)
#endif

/* format string */
#define LOGF_TRACE(key, fmt, ...)  LOG_FORMAT(key, LOG_LEVEL_TRACE, __FUNCTION__, __FILE__, __LINE__, false, fmt, ##__VA_ARGS__)
#define LOGF_DEBUG(key, fmt, ...)  LOG_FORMAT(key, LOG_LEVEL_DEBUG, __FUNCTION__, __FILE__, __LINE__, false, fmt, ##__VA_ARGS__)
#define LOGF_INFO(key,  fmt, ...)  LOG_FORMAT(key, LOG_LEVEL_INFO,  __FUNCTION__, __FILE__, __LINE__, false, fmt, ##__VA_ARGS__)
#define LOGF_WARN(key,  fmt, ...)  LOG_FORMAT(key, LOG_LEVEL_WARN,  __FUNCTION__, __FILE__, __LINE__, false, fmt, ##__VA_ARGS__)
#define LOGF_ERROR(key, fmt, ...)  LOG_FORMAT(key, LOG_LEVEL_ERROR, __FUNCTION__, __FILE__, __LINE__, false, fmt, ##__VA_ARGS__)
#define LOGF_FATAL(key, fmt, ...)  LOG_FORMAT(key, LOG_LEVEL_FATAL, __FUNCTION__, __FILE__, __LINE__, true , fmt, ##__VA_ARGS__)

#define LOGFT(fmt, ...) LOGF_TRACE("main", fmt, ##__VA_ARGS__)
#define LOGFD(fmt, ...) LOGF_DEBUG("main", fmt, ##__VA_ARGS__)
#define LOGFI(fmt, ...) LOGF_INFO ("main", fmt, ##__VA_ARGS__)
#define LOGFW(fmt, ...) LOGF_WARN ("main", fmt, ##__VA_ARGS__)
#define LOGFE(fmt, ...) LOGF_ERROR("main", fmt, ##__VA_ARGS__)
#define LOGFF(fmt, ...) LOGF_FATAL("main", fmt, ##__VA_ARGS__)

#if defined(LOG4X_STATICLIB)
#  define LOG4X_API
#elif defined(WIN32) || defined(_WIN32)
#  if defined(LOG4X_EXPORTS)
#    define LOG4X_API  __declspec(dllexport)
#  else
#    define LOG4X_API  __declspec(dllimport)
#  endif
#else
#  define   LOG4X_API  __attribute__((visibility("default")))
#endif

enum
{
    LOG_LEVEL_TRACE = 0,
    LOG_LEVEL_DEBUG,
    LOG_LEVEL_INFO,
    LOG_LEVEL_WARN,
    LOG_LEVEL_ERROR,
    LOG_LEVEL_FATAL,
};
#endif

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief 初始化日志库
 *
 * @note 
 * 调用日志库其他接口前必须先调用该接口
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_init();

/**
 * @brief 反初始化日志库
 */
LOG4X_API void log4x_uninit();

/**
 * @brief 写日志信息, 默认等级为LOG_LEVEL_INFO
 *
 * @param [in] key 日志模块名
 * @param [in] fmt 打印格式化字符串
 * @param [in] ... 打印信息
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int  log4x_info(const char * key, const char* fmt, ...);

/**
 * @brief 读取配置文件
 *
 * @param [in] path 配置文件路径
 *
 * @return 成功返回0. 失败返回-1.
 *
 * @see log4x_config_fromstr
 */
LOG4X_API int log4x_config(const char * path);

/**
 * @brief 读取配置参数字符串
 *
 * @param [int] str 配置参数字符串
 *
 * @return 成功返回0. 失败返回-1.
 *
 * @see log4x_config
 */
LOG4X_API int log4x_config_fromstr(const char * str);

/**
 * @brief 写日志信息
 *
 * @param [in] key   日志模块名
 * @param [in] level 日志等级
 * @param [in] func  打印信息对应函数名
 * @param [in] file  打印信息对应文件名
 * @param [in] line  打印信息对应行号
 * @param [in] sync  是否同步打印
 * @param [in] fmt   打印格式化字符串
 * @param [in] ...   打印信息
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_push(const char * key, int level, const char * func, const char * file, int line, bool sync, const char* fmt, ...);

/**
 * @brief 使能模块名为key的日志打印
 *
 * @param [in] key    日志模块名
 * @param [in] enable 是否使能
 *                    - true  打开
 *                    - false 关闭
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_enable(const char * key, bool enable);

/**
 * @brief 设置模块日志打印等级
 *
 * @param [in] key   日志模块名
 * @param [in] level 日志等级
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_setlevel(const char * key, int level);

/**
 * @brief 是否打印模块日志到终端显示屏上
 *
 * @param [in] key    日志模块名
 * @param [in] enable 是否使能, 默认打开
 *                    - true  打开
 *                    - false 关闭
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_setdisplay(const char * key, bool enable);

/**
 * @brief 是否打印模块日志文件行号
 *
 * @param [in] key    日志模块名
 * @param [in] enable 是否使能, 默认打开
 *                    - true  打开
 *                    - false 关闭
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_setfileline(const char * key, bool enable);

/**
 * @brief 是否将在模块日志输出到进程日志文件中(同时打印到模块日志与进程日志中)
 *
 * @param [in] key    日志模块名
 * @param [in] enable 是否使能, 默认打开
 *                    - true  打开
 *                    - false 关闭
 *
 * @return 成功返回0. 失败返回-1.
 */
LOG4X_API int log4x_setprocfile(const char * key, bool enable);

LOG4X_API bool log4x_isff(const char * key);

#ifdef __cplusplus
}
#endif

#endif
